#target photoshop

app.bringToFront();

var doc = app.activeDocument;
var allLayers = [];
var selectedLayers = [];

function collectAllLayers(parent, parentPath) {
    var layers = parent.layers || parent.artLayers;
    
    for (var i = layers.length - 1; i >= 0; i--) {
        var layer = layers[i];
        var layerInfo = {
            layer: layer,
            name: layer.name,
            type: layer.typename === "ArtLayer" ? (layer.kind === LayerKind.TEXT ? "text" : "layer") : "group",
            visible: layer.visible,
            parentPath: parentPath.slice(),
            fullPath: parentPath.length > 0 ? parentPath.join("/") + "/" + layer.name : layer.name,
            selected: true,
            hasText: false,
            textContent: "",
            fontSize: 0,
            fontFamily: "",
            textColor: "",
            hasStroke: false
        };
        
        if (layerInfo.type === "text") {
            try {
                var textItem = layer.textItem;
                layerInfo.hasText = true;
                layerInfo.textContent = textItem.contents || "";
                layerInfo.fontSize = Math.round(textItem.size) || 0;
                layerInfo.fontFamily = textItem.font || "";
                
                if (textItem.color && textItem.color.rgb) {
                    var r = Math.round(textItem.color.rgb.red);
                    var g = Math.round(textItem.color.rgb.green);
                    var b = Math.round(textItem.color.rgb.blue);
                    layerInfo.textColor = "rgb(" + r + "," + g + "," + b + ")";
                }
                
                try {
                    var ref = new ActionReference();
                    ref.putIdentifier(charIDToTypeID("Lyr "), layer.id);
                    var layerDesc = executeActionGet(ref);
                    if (layerDesc.hasKey(stringIDToTypeID("layerEffects"))) {
                        var effects = layerDesc.getObjectValue(stringIDToTypeID("layerEffects"));
                        if (effects.hasKey(stringIDToTypeID("frameFX"))) {
                            layerInfo.hasStroke = true;
                        }
                    }
                } catch (e) {}
            } catch (e) {}
        }
        
        allLayers.push(layerInfo);
        
        if (layerInfo.type === "group") {
            var newPath = parentPath.slice();
            newPath.push(layer.name);
            collectAllLayers(layer, newPath);
        }
    }
}

function createPreviewDialog() {
    var dialog = new Window("dialog", "\u9884\u89C8\u5BFC\u51FA\u5217\u8868");
    dialog.alignChildren = ["fill", "top"];
    dialog.spacing = 10;
    dialog.margins = 16;
    
    var searchGroup = dialog.add("group");
    searchGroup.orientation = "row";
    searchGroup.alignChildren = ["left", "center"];
    searchGroup.add("statictext", undefined, "\u641C\u7D22:");
    var searchInput = searchGroup.add("edittext", undefined, "");
    searchInput.characters = 30;
    
    var filterGroup = dialog.add("group");
    filterGroup.orientation = "row";
    filterGroup.alignChildren = ["left", "center"];
    var cbShowText = filterGroup.add("checkbox", undefined, "\u6587\u5B57\u56FE\u5C42");
    cbShowText.value = true;
    var cbShowLayers = filterGroup.add("checkbox", undefined, "\u666E\u901A\u56FE\u5C42");
    cbShowLayers.value = true;
    var cbShowGroups = filterGroup.add("checkbox", undefined, "\u7EC4");
    cbShowGroups.value = true;
    
    var statsGroup = dialog.add("group");
    statsGroup.orientation = "row";
    statsGroup.alignChildren = ["left", "center"];
    var statsText = statsGroup.add("statictext", undefined, "\u603B\u8BA1: 0 | \u5DF2\u9009: 0");
    
    var listPanel = dialog.add("panel", undefined, "\u56FE\u5C42\u5217\u8868");
    listPanel.alignChildren = ["fill", "fill"];
    listPanel.margins = 10;
    
    var listBox = listPanel.add("listbox", undefined, [], {
        numberOfColumns: 5,
        showHeaders: true,
        columnTitles: ["\u9009\u62E9", "\u540D\u79F0", "\u7C7B\u578B", "\u8DEF\u5F84", "\u6587\u5B57\u4FE1\u606F"],
        columnWidths: [50, 200, 80, 250, 300]
    });
    listBox.preferredSize = [900, 400];
    
    var buttonGroup1 = dialog.add("group");
    buttonGroup1.orientation = "row";
    buttonGroup1.alignChildren = ["center", "center"];
    var btnSelectAll = buttonGroup1.add("button", undefined, "\u5168\u9009");
    var btnDeselectAll = buttonGroup1.add("button", undefined, "\u53D6\u6D88\u5168\u9009");
    var btnInvertSelection = buttonGroup1.add("button", undefined, "\u53CD\u9009");
    var btnSelectVisible = buttonGroup1.add("button", undefined, "\u9009\u62E9\u53EF\u89C1");
    
    var buttonGroup2 = dialog.add("group");
    buttonGroup2.orientation = "row";
    buttonGroup2.alignChildren = ["center", "center"];
    var btnOk = buttonGroup2.add("button", undefined, "\u5F00\u59CB\u5BFC\u51FA", {name: "ok"});
    var btnCancel = buttonGroup2.add("button", undefined, "\u53D6\u6D88", {name: "cancel"});
    
    function updateList(filterText) {
        listBox.removeAll();
        var filter = (filterText || "").toLowerCase();
        var totalCount = 0;
        var selectedCount = 0;
        
        for (var i = 0; i < allLayers.length; i++) {
            var layerInfo = allLayers[i];
            
            if (!cbShowText.value && layerInfo.type === "text") continue;
            if (!cbShowLayers.value && layerInfo.type === "layer") continue;
            if (!cbShowGroups.value && layerInfo.type === "group") continue;
            
            if (filter.length > 0) {
                var matchName = layerInfo.name.toLowerCase().indexOf(filter) >= 0;
                var matchPath = layerInfo.fullPath.toLowerCase().indexOf(filter) >= 0;
                var matchText = layerInfo.textContent.toLowerCase().indexOf(filter) >= 0;
                if (!matchName && !matchPath && !matchText) continue;
            }
            
            totalCount++;
            if (layerInfo.selected) selectedCount++;
            
            var typeText = layerInfo.type === "text" ? "\u6587\u5B57" : (layerInfo.type === "group" ? "\u7EC4" : "\u56FE\u5C42");
            var textInfo = "";
            
            if (layerInfo.hasText) {
                textInfo = layerInfo.textContent.substring(0, 20);
                if (layerInfo.textContent.length > 20) textInfo += "...";
                textInfo += " | " + layerInfo.fontFamily + " " + layerInfo.fontSize + "px";
                if (layerInfo.textColor) textInfo += " | " + layerInfo.textColor;
                if (layerInfo.hasStroke) textInfo += " | \u63CF\u8FB9";
            }
            
            var item = listBox.add("item", layerInfo.selected ? "\u2611" : "\u2610");
            item.subItems[0].text = layerInfo.name;
            item.subItems[1].text = typeText;
            item.subItems[2].text = layerInfo.fullPath;
            item.subItems[3].text = textInfo;
            
            item.layerIndex = i;
        }
        
        statsText.text = "\u603B\u8BA1: " + totalCount + " | \u5DF2\u9009: " + selectedCount;
    }
    
    searchInput.onChanging = function() {
        updateList(this.text);
    };
    
    cbShowText.onClick = function() { updateList(searchInput.text); };
    cbShowLayers.onClick = function() { updateList(searchInput.text); };
    cbShowGroups.onClick = function() { updateList(searchInput.text); };
    
    listBox.onChange = function() {
        if (this.selection) {
            var layerIndex = this.selection.layerIndex;
            allLayers[layerIndex].selected = !allLayers[layerIndex].selected;
            this.selection.text = allLayers[layerIndex].selected ? "\u2611" : "\u2610";
            updateList(searchInput.text);
        }
    };
    
    btnSelectAll.onClick = function() {
        for (var i = 0; i < allLayers.length; i++) {
            allLayers[i].selected = true;
        }
        updateList(searchInput.text);
    };
    
    btnDeselectAll.onClick = function() {
        for (var i = 0; i < allLayers.length; i++) {
            allLayers[i].selected = false;
        }
        updateList(searchInput.text);
    };
    
    btnInvertSelection.onClick = function() {
        for (var i = 0; i < allLayers.length; i++) {
            allLayers[i].selected = !allLayers[i].selected;
        }
        updateList(searchInput.text);
    };
    
    btnSelectVisible.onClick = function() {
        for (var i = 0; i < allLayers.length; i++) {
            allLayers[i].selected = allLayers[i].visible;
        }
        updateList(searchInput.text);
    };
    
    updateList("");
    
    if (dialog.show() === 1) {
        selectedLayers = [];
        for (var i = 0; i < allLayers.length; i++) {
            if (allLayers[i].selected) {
                selectedLayers.push(allLayers[i]);
            }
        }
        return true;
    }
    
    return false;
}

function main() {
    if (!doc) {
        alert("\u8BF7\u5148\u6253\u5F00\u4E00\u4E2A\u6587\u6863");
        return;
    }
    
    collectAllLayers(doc, []);
    
    if (allLayers.length === 0) {
        alert("\u6CA1\u6709\u627E\u5230\u4EFB\u4F55\u56FE\u5C42");
        return;
    }
    
    if (createPreviewDialog()) {
        alert("\u5DF2\u9009\u62E9 " + selectedLayers.length + " \u4E2A\u56FE\u5C42\u5BFC\u51FA\n\n\u8BF7\u4F7F\u7528 'Export Layers To Files (Fast).jsx' \u8FDB\u884C\u5B9E\u9645\u5BFC\u51FA");
    }
}

main();

